#include <iostream>
#include <SDL/SDL.h>
#include <GL/gl.h>
#include <GL/glu.h>

using namespace std;

int main(int argc, char **argv)
{

	cout << "Hello OpenGL" << endl;
	// Initialize SDL with best video mode
	if (SDL_Init(SDL_INIT_VIDEO) != 0)
	{
		// Failure
		cerr << "Error: " << SDL_GetError() << endl;
		return EXIT_FAILURE;
	}
	// Success
	cout << "SDL initialized." << endl;

	const SDL_VideoInfo* info = SDL_GetVideoInfo();
	int vidFlags= SDL_OPENGL | SDL_GL_DOUBLEBUFFER;
	if (info->hw_available)
	{
		vidFlags |= SDL_HWSURFACE;
	}
	else
	{
		vidFlags |= SDL_SWSURFACE;
	}
	int bpp = info->vfmt->BitsPerPixel;
	//SDL_Surface *screen =
		SDL_SetVideoMode(640, 480, bpp, vidFlags);
	glViewport( 0, 0, 640, 480);
	glMatrixMode( GL_PROJECTION);
	glEnable( GL_DEPTH_TEST);
	gluPerspective( 45, (float)480/640, 0.1, 100);
	glMatrixMode( GL_MODELVIEW);

	// All that boring screen initialization is done. Let's deal with textures.
	
	glClearColor(0.0, 0.0, 0.0, 0.0);

	// Enable 2D textures
	glEnable(GL_TEXTURE_2D);

	// TODO LOAD IMAGE HERE. You should make it a 32x32 pixel RGB image.
	unsigned char imageData[32*32*4]; // Put the data here.
	
	// For now we put worthless data into imageData.
	for(int i = 0; i < 32*32*4; i++)
	{
		imageData[i] = (i%256); 
	}

	// Create a place in GL to reference the memory.
	unsigned int images[1];
	glGenTextures(1, images);

	// All things referencing GL_TEXTURE_2D will refer to the handle that
	// images[0] contains.
	glBindTexture(GL_TEXTURE_2D, images[0]);

	// Texture filters: rendering the image when enlarged or shrunk.
	// When enlarging, use nearest neighbor.
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	// When reducing size, use nearest neighbor.
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

	/*
	 * glTexImage2D(GLenum target, GLint level, GLint internalFormat,
	 * 	GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type,
	 * 	const GLvoid* texels);
	 * 
	 * target - determines texture type, usually GL_TEXTURE_2D
	 * level - Used in mipmaps. I have no idea, we'll use 0 for now. 
	 * internal format - Describes how the texture is stored in video memory:
	 * 	GL_ALPHA
	 *  GL_LUNINANCE
	 *  GL_LUMINANCE_ALPHA
	 *  GL_INTENSITY
	 *  GL_RGB	(Also GL_RGB8)
	 *  GL_RGBA	(Also GL_RGBA8)
	 * width - the width of the image (must be power of 2)
	 * height - the height of the image (must be power of 2)
	 * border - Indicates whether there is a border around the image or not,
	 *  0 - no border
	 *  1 - border with color set in the GL_TEXTURE_BORDER_COLOR parameter
	 * format - The format of the image data contained in the texels array:
	 * 	GL_COLOR_INDEX - color index values
	 *  GL_RED, GL_GREEN, GL_BLUE - Red, Green, or Blue pixel values.
	 *  GL_ALPHA - Alpha pixel values
	 *  GL_RGB - Red, Green, Blue values
	 *  GL_RGBA - Red, Green, Blue, Alpha values
	 *  GL_LUMINANCE - Grayscale values (luminance)
	 *  GL_LUMINANCE_ALPHA - Grayscale values with alpha (luminance with alpha)
	 * type - The data type of the texture data that is being loaded
	 * 	GL_BITMAP	A single bit for each pixel
	 * 	GL_BYTE		Signed 8-bit integer
	 * 	GL_UNSIGNED_BYTE	Unsigned 8-bit integer
	 * 	GL_SHORT	Signed short 16-bit integer
	 *  GL_UNSIGNED_SHORT	Unsigned short 16-bit integer
	 * 	GL_INT		Signed 32-bit integer
	 * 	GL_UNSIGNED_INT	Unsigned 32-bit integer
	 * 	GL_FLOAT	Single-precision floating point (4 bytes)
	 * texels
	 */
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE,
			imageData);

	// Examples:
	
	// Deleting textures would be:
	// glDeleteTextures(1, images);
	
	// Determine if the textures are available to the graphics hardware:
	// boolean residences[1]; // Individual results are stored here.
	// glAreTexturesResident(1, images, residences);

	// If there are too many images in video memory they will have to be
	// pushed off. Prioritize which ones to be pushed off first, in the range
	// [0, 1], where 0 is lowest, 1 is highest.
	// float priorities[1];
	// priorities[0] = 1.0f // Highest priority because we are awesome.
	// glPrioritize(1, images, priorities);

	// loop forever
	SDL_Event event;
	while (true)
	{
		if (SDL_PollEvent(&event) )
		{
			if (event.type == SDL_QUIT)
			{
				break; // Leave this loop.
			}
		}
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		glLoadIdentity();
		glTranslatef(0, 0, -20);
		glRotatef(0, 0, 0, 1);
		glTranslatef(-5, -5, 0);
		glPointSize(5);
		
		// Make image texture.
		glBegin(GL_POLYGON);
		// lower left
		glTexCoord2f(0.0f, 0.0f); 
		glVertex3f(-0.5f, 0.5f, 0.5f);
		// lower right
		glTexCoord2f(1.0f, 0.0f); 
		glVertex3f(0.5f, 0.5f, 0.5f);
		// upper right
		glTexCoord2f(1.0f, 1.0f); 
		glVertex3f(0.5f, -0.5f, 0.5f);
		// upper left
		glTexCoord2f(0.0f, 1.0f); 
		glVertex3f(-0.5f, -0.5f, 0.5f);
		glEnd();
		// End make image texture.

		SDL_GL_SwapBuffers();
	}
	
	cout << "We are done now." << endl;
	return EXIT_SUCCESS;
}
